#ifndef _MESSAGEUTIL_H_
#define _MESSAGEUTIL_H_

#include "protobuf.h"
#include "package.h"

#ifdef _WIN32
#include "google\protobuf\io\coded_stream.h"
#elif __linux__
#include "google/protobuf/io/coded_stream.h"
#include <stdio.h>
#define sprintf_s snprintf
#endif

using namespace google::protobuf;

class MessageUtil
{
public:
	static bool serializePackageToString(const Message& msg,PackageHeader::MsgType type,unsigned int command,unsigned int serialnum,unsigned int dstaddr,std::string* output)
	{
		std::string data;
		if(!MessageUtil::serializeToString(msg,&data))
			return false;
		PackageHeader header;
		header.type=type;
		header.command=command;
		header.serialnum=serialnum;
		header.dstaddr=dstaddr;
		header.off=PackageHeaderLength;
		header.bodysize=data.size();
		
		output->clear();
		output->resize(PackageHeaderLength);
		header.write(&*output->begin());
		output->append(data);
		return true;
	}
    static bool serializeToString(const Message& msg,std::string* output)
	{
		std::string tname=msg.GetTypeName();
		char tmp[256];
		tmp[0]=0;
		sprintf_s(tmp,256,"%c%s",(char)tname.size(),tname.c_str());
		output->append(tmp);
		std::string content;
		if(!msg.SerializeToString(&content))
			return false;
		output->append(content);
		return true;
	}
	static Message* parseFromString(const std::string& data)
	{
	    return parseFromArray(&*data.begin(),data.size());	
	}
	static std::string getType(const char* data,size_t size)
	{
		std::string type;
		do{
			google::protobuf::io::CodedInputStream stream((const uint8*)data,size);
			uint8 namesize=0;
			stream.ReadRaw(&namesize,1);
			if(namesize+1>size)
				break;
			type.resize(namesize);
			stream.ReadRaw((void*)type.c_str(),namesize);
		}while(false);
		return type;
	}
	static Message* parseFromArray(const char* data,size_t size)
	{
		Message* message = NULL;
		do{
			google::protobuf::io::CodedInputStream stream((const uint8*)data,size);
			uint8 namesize=0;
			stream.ReadRaw(&namesize,1);
			if(namesize+1>size)
				break;
			std::string type;
			type.resize(namesize);
			stream.ReadRaw((void*)type.c_str(),namesize);
			
			const Descriptor* des=DescriptorPool::generated_pool()->FindMessageTypeByName(type);
			if(!des)
				break;
			const Message* prototype = MessageFactory::generated_factory()->GetPrototype(des);
			if (!prototype)
			    break;
			
			message = prototype->New();
			if(!message->ParseFromCodedStream(&stream))
			{
				delete message;
				message=NULL;
			}
		}while(false);
		return (message);
	}
};

#endif